<script setup lang="ts">/**
 * 文件选择器
 * @property modelValue [Boolean] [default: false] [desc: 是否显示]] 使用 v-model 绑定一个变量来控制组件的开启与关闭
 * @property titel [String] [default: '选择文件'] [desc: 标题]
 * @property titelSize [Number] [default: 30] [desc: 标题字体大小]
 * @property titelColor [String] [default: '#373737'] [desc: 标题字体颜色]
 * @property navBgColor [String] [default: '#fff'] [desc: 导航栏颜色]
 */
import { getPermission } from "@/utils/fileUtils";

const props = defineProps({
  titel: {
    type: String,
    default: '选择文件'
  },
  titelSize: {
    type: [String, Number],
    default: 30
  },
  titelColor: {
    type: String,
    default: '#373737'
  },
  /** 导航栏颜色 */
  navBgColor: {
    type: String,
    default: '#F8F8F8'
  },
})

const emit = defineEmits(['change'])

const isOpen = defineModel();

const titelStyle = computed(() => {
  return {
    fontSize: props.titelSize + 'rpx',
    color: props.titelColor
  }
})

// 无法访问
const inaccessible = ref(false)

// 能否退出标志
const isExit = ref(true)

// 地址栏记录栈
const addressBar = ref([])

// 根目录
const rootAddress = ref({})

// 文件夹列表
const folderList = ref([])

// 文件列表
const fileList = ref([])

let filterReg = "";

// 选中文件列表
const selectList = ref([])

const allCheked = computed(() => selectList.value.length === fileList.value.length);

/** 打开组件 */
async function open() {
  if(!await getPermission()) return;

  isOpen.value = true
  getRootDirectory();
  listenerEvent();
  uni.hideTabBar();
}

function close(isCommit = false) {
  if(isCommit) {
    emit('change', selectList.value);
  }else{
    emit('change', []);
  }

  isOpen.value = false
  addressBar.value = [];
  folderList.value = [];
  fileList.value = [];
  selectList.value = [];
  rootAddress.value = {};
  destroyEvent();
  uni.showTabBar();
}


function handerCommit() {
  close(true);
}

// 获取根目录
function getRootDirectory() {
  inaccessible.value = false;
  // 修改退出状态，以便在点击返回按钮时最后一层返回的是根目录，再点击一次才会退出
  isExit.value = false;
  addressBar.value = [];
  const environment = plus.android.importClass("android.os.Environment");
  environment.getExternalStorageState() === environment.MEDIA_MOUNTED;
  const sdRoot = environment.getExternalStorageDirectory();
  const rootName = plus.android.invoke(sdRoot, "getName");
  rootAddress.value = {
    name: rootName,
    file: sdRoot,
  };

  const files = plus.android.invoke(sdRoot, "listFiles");

  getFileList(files);
  rootAddress.value.folderList = folderList.value;
  rootAddress.value.fileList = fileList.value;
}

// 打开文件夹
function toFolder(event) {
  isExit.value = false;
  addressBar.value.push(event);
  const files = plus.android.invoke(event.file, "listFiles");
  getFileList(files);
}

/** 选择文件 */
function selectFile(event, index) {
  event.select = !event.select;
  if (event.select) {
    const item = {
      ...event
    }
    delete item.file;
    delete item.select;
    selectList.value.push(item);
  } else {
    selectList.value.splice(index, 1);
  }
}

/**  全选 */
function allSelect() {
  if (allCheked.value) {
    fileList.value.forEach((item, index) => {
      item.select = false;
      selectList.value = [];
    })
  } else {
    selectList.value = fileList.value.map((file, index) => {
      file.select = true;
      const item = {
        ...file
      }
      delete item.file;
      delete item.select;
      return item;
    })
  }
}

/** 获取文件列表 */
function getFileList(files) {
  inaccessible.value = false;
  folderList.value = [];
  fileList.value = [];
  selectList.value = [];

  if (!(Object.prototype.toString.call(files) === '[object Array]')) {
    inaccessible.value = true;
    uni.showToast({
      icon: 'none',
      title: '请确认授权访问',
      duration: 2000
    });
    return;
  }

  files.forEach((file, index) => {
    // 过滤隐藏文件
    if (plus.android.invoke(file, "isHidden")) return;
    const fileName = plus.android.invoke(file, "getName");
    // 判断是文件还是文件夹
    if (plus.android.invoke(file, "isDirectory")) {
      folderList.value.push({
        name: fileName,
        file,
      });
    } else {
      if (fileList.value.length > 0) {
        if (fileName.search(filterReg) < 0) {
          return;
        }
      }

      // 文件类型
      const type = fileName.split('.').pop();

      const FileInputStream = plus.android.importClass("java.io.FileInputStream");

      const fileInputStream = new FileInputStream(file);

      const fileSize = fileInputStream.available();

      let sizeShow = ""

      if (fileSize < 1024) {
        sizeShow = fileSize + "B";
      } else if (fileSize < 1024 * 1024) {
        sizeShow = (fileSize / 1024).toFixed(2) + "KB";
      } else if (fileSize < 1024 * 1024 * 1024) {
        sizeShow = (fileSize / 1024 / 1024).toFixed(2) + "MB";
      } else {
        sizeShow = (fileSize / 1024 / 1024 / 1024).toFixed(2) + "GB";
      }

      const path = plus.android.invoke(file, "getPath");

      fileList.value.push({
        name: fileName,
        file, type,
        select: false,
        size: fileSize,
        sizeShow,
        path
      });
    }
  });
  folderList.value.sort((a, b) => a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1');
  fileList.value.sort((a, b) => a.name.toUpperCase() > b.name.toUpperCase() ? '1' : '-1');
}

// 返回根目录
function backRoot() {
  isExit.value = true;
  addressBar.value = [];
  folderList.value = rootAddress.value.folderList;
  fileList.value = rootAddress.value.fileList;
}


// 点击返回
function backAddress() {
  const len = addressBar.value.length;
  if (len > 1) {
    const index = len - 2;
    const event = addressBar.value[index];
    backFolder(event, index);
  } else if (len == 1) {
    backRoot()
  }else{
    if(isExit.value){
      close();
    }else {
      isExit.value = true;
      uni.showToast({
        title: '再操作一次退出文件选择',
        icon: 'none',
        duration: 1000
      });
    }
  }
}

// 返回上级文件夹
function backFolder(event, index) {
  const len = addressBar.value.length;
  if (index + 1 == len) {
    return;
  }
  addressBar.value.splice(index + 1, len - index - 1);
  const files = plus.android.invoke(event.file, "listFiles");
  getFileList(files);
}

let toastFn = null;

let quitFn = null;

/** 监听按键操作 */
function listenerEvent() {
  plus.key.addEventListener('backbutton', backAddress, false);
  toastFn = plus.nativeUI.toast;
  quitFn = plus.runtime.quit;

  plus.nativeUI.toast = () => {}
  plus.runtime.quit = () => {}

  // 隐藏顶部电池,时间等信息
  // plus.navigator.setFullscreen(true);
  //隐藏虚拟按键
  // plus.navigator.hideSystemNavigation()
}
/** 移除按键监听 */
function destroyEvent() {
  // 需要移除具体的回调函数引用
  plus.key.removeEventListener('backbutton', backAddress);
  if(toastFn){
    plus.nativeUI.toast = toastFn;
  }
  if(quitFn){
    plus.runtime.quit = quitFn;
  }
}

onMounted(() => {
  if(isOpen.value){
    open();
  }
})

watch(isOpen, (newValue) => {
  if (newValue) {
    open();
  }
})
</script>

<template>
  <view class="file-outer-box" @touchmove.prevent v-if="isOpen">
    <view class="file-titel" :style="{backgroundColor: navBgColor}">
      <view class="file-nav-leftBox" @click="backAddress">
        <uni-icons type="left" size="20"></uni-icons>
      </view>
      <text class="file-titel-content" :style="titelStyle">
        {{ titel }}
      </text>
      <view class="file-nav-rightBox" @click="handerCommit" v-if="selectList.length">
        提交
      </view>
      <view class="file-nav-rightBox" @click="close()" v-else>
        <uni-icons type="close" size="24" />
      </view>
    </view>
    <view class="file-address">
      <view class="root-box" @click="backRoot">
        内部存储
      </view>
      <scroll-view :scroll-x="true" class="address-scroll">
        <view class="address-box" v-for="(item,index) in addressBar" @click="backFolder(item,index)">
          <uni-icons type="right" size="20"></uni-icons>
          {{ item.name }}
        </view>
      </scroll-view>
      <view class="file-all-select" v-if="fileList.length"  @click="allSelect">
        <uni-icons type="checkbox-filled" size="30" v-if="allCheked" />
        <uni-icons type="circle" size="30" v-else />
      </view>
    </view>
    <scroll-view :scroll-y="true" class="file-folder-box">
      <view class="select-tips" v-if="inaccessible">
        <view style="line-height: 40rpx;">
          无法访问的文件夹
        </view>
        <view style="line-height: 40rpx;">
          建议前往安卓存储访问框架查看文件
        </view>
      </view>
      <view class="folder-box" v-for="item in folderList" @click="toFolder(item)">
        <view class="folder-name-box">
          <uni-icons type="folder-add-filled" size="30"></uni-icons>
          <view class="name-box">{{ item.name }}</view>
        </view>
        <view>
          <uni-icons type="folder-add-filled" size="30"></uni-icons>
        </view>
      </view>
      <view class="file-box" v-for="(item,index) in fileList" @click="selectFile(item, index)">
        <view class="file-name-box">
          <!--          <image :src="fileImg" mode="widthFix" class="file-img" v-if="item.type == 'file'" />-->
          <!--          <image :src="txtImg" mode="widthFix" class="file-img" v-if="item.type == 'txt'" />-->
          <!--          <image :src="docImg" mode="widthFix" class="file-img" v-if="item.type == 'doc'" />-->
          <!--          <image :src="pdfImg" mode="widthFix" class="file-img" v-if="item.type == 'pdf'" />-->
          <view class="name-box">
            {{ item.name }}
          </view>
        </view>
        <view>

          <uni-icons type="checkbox-filled" size="30" v-if="item.select" />
          <uni-icons type="circle" size="30" v-else />
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<style lang="scss" scoped>
.file-outer-box {
  width: 100%;
  height: calc(100% - 120rpx);
  position: fixed;
  top: 80rpx;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1070;
  padding-bottom: 40rpx;
  background-color: #fff;
  font-size: 14px;

  .file-titel {
    width: calc(100% - 64rpx);
    height: 80rpx;
    line-height: 80rpx;
    text-align: center;
    padding: 0 32rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .file-nav-leftBox {
      width: 60rpx;
      height: 100%;
      display: flex;
      align-items: center;

      .file-back-img {
        width: 36rpx;
      }
    }

    .file-titel-content {
      flex: auto;
    }

    .file-nav-rightBox {
      width: 60rpx;
      height: 100%;
    }
  }

  .file-address {
    width: 686rpx;
    height: 60rpx;
    background-color: #FBFBFB;
    padding: 0 32rpx;
    display: flex;
    color: #373737;
    font-size: 24rpx;

    .address-scroll {
      //flex: 1;
      white-space: nowrap;
      height: 100%;
      max-width: 508rpx;

      .address-box {
        height: 60rpx;
        line-height: 60rpx;
        display: inline-block;

        .to-img-box {
          width: 20rpx;
        }
      }
    }

    .root-box {

      width: 116rpx;
      height: 60rpx;
      line-height: 60rpx;
      display: inline-block;
      box-shadow: 10rpx 0 10rpx -10rpx rgba(8, 8, 8, 0.3);
      .to-img-box {
        width: 20rpx;
      }
    }

    .file-all-select {
      text-align: right;
      width: 62rpx;
    }
  }

  .file-folder-box {
    height: calc(100% - 148rpx);

    .folder-box {
      height: 120rpx;
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin: 0 32rpx;
      border-bottom: 1px solid #EEEEEE;

      .folder-name-box {
        width: 80%;
        display: flex;
        align-items: center;
        flex-wrap: wrap;

        .folder-img {
          width: 72rpx;
          margin-right: 16rpx;
        }

        .name-box {
          width: calc(100% - 100rpx);
          overflow: hidden;
          word-wrap: break-word;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
        }
      }

      .toFolder-img {
        width: 28rpx;
      }
    }

    .select-tips {
      width: 100%;
      height: 160rpx;
      text-align: center;
      font-size: 32rpx;
      color: #888;
      padding-top: 60rpx;
    }

    .file-box {
      height: 120rpx;
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin: 0 32rpx;
      border-bottom: 1px solid #EEEEEE;

      .file-name-box {
        width: 80%;
        display: flex;
        align-items: center;

        .file-img {
          width: 72rpx;
          margin-right: 16rpx;
        }

        // .type-file{
        // 	width: 60rpx;
        // 	margin-left: 10rpx;
        // }
        .name-box {
          width: calc(100% - 100rpx);
          overflow: hidden;
          word-wrap: break-word;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
        }
      }

      .select-img {
        width: 32rpx;
      }
    }

  }

  .select-foot-btn {
    width: calc(100% - 64rpx);
    margin-top: 20rpx;
  }
}
</style>
